﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Sofire.Expressions;
using System.Xml.Linq;

namespace Sofire.Data.XSql
{
    internal class XSqlExpressionNode : XSqlNameNodeBase, IXSqlExpressionNode
    {
        public const string NodeName = "expression";

        public override XSqlType Type
        {
            get { return XSqlType.Expression; }
        }

        private string _Expression;
        public string Expression
        {
            get
            {
                return this._Expression;
            }
            set
            {
                this._Expression = value;
            }
        }

        public override XObject CreateXObject()
        {
            XElement element = new XElement(NodeName);
            element.SetAttributeValue(XSqlAttributes.Name, this.Name);
            element.SetValue(this._Expression);
            return element;
        }

        protected override void Load(XmlNode node)
        {
            base.Load(node);
            this._Expression = node.InnerText;
            if(this._Expression == null
                || (this._Expression = this._Expression.Trim()).Length == 0) this.ThrowException(XSqlError.UnfoundText, NodeName);
        }

        private Expression _compiledExpression;

        public override string Compile(XSqlParameterCollection parameters)
        {
            return Convert.ToString(this.CompileObject(parameters));
        }

        //- Parameters 节点下的编译
        public object CompileObject(XSqlParameterCollection parameters)
        {
            if(this._compiledExpression == null)
            {
                lock(this)
                {
                    if(this._compiledExpression == null)
                    {
                        this._compiledExpression = this.Document.CreateExpression(this._Expression);
                    }
                }
            }

            EvaluateParameterHandler handler = (name, args) =>
            {
                args.Result = parameters.GetValue(name);
            };
            this._compiledExpression.EvaluateParameter += handler;
            try
            {
                return _compiledExpression.Evaluate();
                //if(this._ValueType == null) return o;
                //System.Data.DbType type;
                //return XSqlBindItem.ConvertValue(o, this._ValueType, out type);
            }
            finally
            {
                this._compiledExpression.EvaluateParameter -= handler;
            }
        }

        public override string ToString()
        {
            return this._Expression;
        }
    }
}
